package com.vic.framework.helper;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.vic.framework.annotation.Aspect;
import com.vic.framework.annotation.Service;
import com.vic.framework.proxy.AspectProxy;
import com.vic.framework.proxy.Proxy;
import com.vic.framework.proxy.ProxyManager;
import com.vic.framework.proxy.TransactionProxy;
/**
 * AOP辅助类
 * @author VIC
 *
 */
public final class AopHelper {
	
	private static final Logger logger = LoggerFactory.getLogger(AopHelper.class);
	static {
		try {
			
			Map<Class<?>, Set<Class<?>>> proxyMap = creatProxyMap();
			Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
			for(Map.Entry<Class<?>, List<Proxy>> entry: targetMap.entrySet()) {
				Class<?> targetClass = entry.getKey();//目标类
				List<Proxy> proxyList = entry.getValue();//目标类对应的多个切面类
				Object proxy = ProxyManager.createProxy(targetClass, proxyList);//生成代理类
				BeanHelper.setBean(targetClass, proxy);
				
			}
		}catch(Exception e){
			logger.error("aop failure", e);
		}
	}

	/**
	 * 获得Aspect注解的目标类Set集合
	 */
	private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception{
		Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
		Class<? extends Annotation> annotation = aspect.value();
		if(annotation != null  &&  !annotation.equals(Aspect.class)){
			targetClassSet.addAll(ClassHelper.getClassByAnnotation(annotation));
		}
		return targetClassSet;
	}

	/**
	 * 获得代理类（切面类  即加了Aspect注解的类）和目标类之间的关系
	 *  代理类需要继承AspectProxy抽象类，同时还需要带有Aspect注解
	 */
	private static Map<Class<?>, Set<Class<?>>> creatProxyMap() throws Exception{
		Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>();
		/*Set<Class<?>> proxyClassSet = Classhelper.getClassByAnnotation(Aspect.class);//获得所有的切面类
		for(Class<?> proxyClass : proxyClassSet) {
			Aspect aspect = proxyClass.getAnnotation(Aspect.class);
			Set<Class<?>> targetClassSet = createTargetClassSet(aspect);//获得当前切面类的目标类
			proxyMap.put(proxyClass, targetClassSet);
		}*/
		/*----->*/
		addAspectProxy(proxyMap);
		addTransactionProxy(proxyMap);
		return proxyMap;
	}
	
	/**切面类和目标类关联起来*/
	private static void addAspectProxy(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception{
		Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
		for(Class<?> proxyClass : proxyClassSet){
			if(proxyClass.isAnnotationPresent(Aspect.class)) {
				Aspect aspect = proxyClass.getAnnotation(Aspect.class);
				Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
				proxyMap.put(proxyClass, targetClassSet);
			}
		}
	}
	
	/**事务切面 和service关联起来*/
	private static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> proxyMap){
		Set<Class<?>> serviceClassSet = ClassHelper.getClassByAnnotation(Service.class);
		proxyMap.put(TransactionProxy.class, serviceClassSet);
	}
	
	
	/**
	 * 分析目标类和代理对象(切面类)列表之间的映射关系
	 */
	private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
		Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
		for(Map.Entry<Class<?>, Set<Class<?>>> entry : proxyMap.entrySet()) {
			Class<?> proxyClass = entry.getKey();
			Set<Class<?>> targetClassSet = entry.getValue();
			for(Class<?> targetClass :  targetClassSet) {
				Proxy proxy = (Proxy) proxyClass.newInstance();
				if(targetMap.containsKey(targetClass)) {
					targetMap.get(targetClass).add(proxy);
				}else {
					targetMap.put(targetClass,new ArrayList<Proxy>(Arrays.asList(proxy)));
				}
			}
		}
		return targetMap;
	}
	
	
}
